#include "item-cache.h"

using namespace std;

struct CacheData ItemCache::get_item_type_info(uint32 item_id) {
  auto it = memory_cache_.find(item_id);
  if (it != memory_cache_.end()) {
    return it->second;
  }
  // 未命中, 从游戏中获取
  auto data = fetch_from_game(item_id);
  memory_cache_[item_id] = data;
  return data;
}

string read_string_from_file(ifstream &file) {
  size_t len;
  file.read(reinterpret_cast<char *>(&len), sizeof(len));
  string str(len, '\0');
  file.read(&str[0], len);
  return str;
}

void write_string_to_file(ofstream &file, const string &str) {
  size_t len = str.size();
  file.write(reinterpret_cast<const char *>(&len), sizeof(len));
  file.write(str.c_str(), len);
}

ItemCache::ItemCache(shared_ptr<Game> game, const string &cache_file)
    : game_{game}, cache_file_{cache_file} {
  load_from_disk();
}

ItemCache::~ItemCache() { save_to_disk(); }

void ItemCache::load_from_disk() {
  std::ifstream file(cache_file_, std::ios::binary);
  if (!file) {
    dbgprintu8("codergege [%s][%03d] Failed to open cache file for reading.\n",
               __FUNCTION__, __LINE__);
    return;
  }

  size_t size;
  file.read(reinterpret_cast<char *>(&size), sizeof(size));

  for (size_t i = 0; i < size; ++i) {
    int item_id;
    struct CacheData data;

    // 读取item_id
    file.read(reinterpret_cast<char *>(&item_id), sizeof(item_id));

    // 读取 uint32 字段
    file.read(reinterpret_cast<char *>(&data.type_index),
              sizeof(data.type_index));
    file.read(reinterpret_cast<char *>(&data.subtype_index),
              sizeof(data.subtype_index));

    // 读取字符串字段
    data.type = read_string_from_file(file);
    data.subtype = read_string_from_file(file);

    memory_cache_[item_id] = data;
  }
}

void ItemCache::save_to_disk() {
  std::ofstream file(cache_file_, std::ios::binary | std::ios::trunc);
  if (!file) {
    dbgprintu8("codergege [%s][%03d] Failed to open cache file for writing.\n",
               __FUNCTION__, __LINE__);
    return;
  }

  size_t size = memory_cache_.size();
  file.write(reinterpret_cast<const char *>(&size), sizeof(size));

  for (const auto &pair : memory_cache_) {
    // 写入item_id
    file.write(reinterpret_cast<const char *>(&pair.first), sizeof(pair.first));

    const struct CacheData &data = pair.second;

    // 写入unsigned int字段
    file.write(reinterpret_cast<const char *>(&data.type_index),
               sizeof(data.type_index));
    file.write(reinterpret_cast<const char *>(&data.subtype_index),
               sizeof(data.subtype_index));

    // 写入字符串字段
    write_string_to_file(file, data.type);
    write_string_to_file(file, data.subtype);
  }
}

struct CacheData ItemCache::fetch_from_game(uint32 item_id) {
  struct CacheData data;
  data.type_index = game_->get_item_type_index(item_id);
  data.type = game_->get_item_type(data.type_index);
  data.subtype_index = game_->get_item_subtype_index(item_id);
  data.subtype = game_->get_item_subtype(data.type_index, data.subtype_index);
  return data;
}
